#ifndef _UTILEX_SAFEPTR_HPP_
#define _UTILEX_SAFEPTR_HPP_

#include <crt_util.h>

#ifdef __cplusplus


struct default_free_safeptr
{
	static void* default_value()
	{
		return 0;
	}
	template<class _Ptr> static bool equal_to(_Ptr l, _Ptr r)
	{
		return l == r;
	}
	template<class _Ptr> static void destroy(_Ptr p)
	{
		if (p != NULL) {
			heap_free(p);
			p = NULL;
		}
	}
};

struct default_safeptr
{
	static void* default_value()
	{
		return 0;
	}
	template<class _Ptr> static bool equal_to(_Ptr l, _Ptr r)
	{
		return l == r;
	}
	template<class _Ptr> static void destroy(_Ptr p)
	{
		if (p != NULL) {
			delete p;
			p = NULL;
		}
	}
};

struct default_array_safeptr
{
	static void* default_value()
	{
		return 0;
	}
	template<class _Ptr> static bool equal_to(_Ptr l, _Ptr r)
	{
		return l == r;
	}
	template<class _Ptr> static void destroy(_Ptr p)
	{
		if (p != NULL) {
			delete[]p;
			p = NULL;
		}
	}
};


template<class _Ptr, class _Traits = default_safeptr>
class SafePtr
{
public:
	SafePtr()
	{
		m_p = (_Ptr)m_tr.default_value();
	}
	SafePtr(_Ptr p) : m_p(p)
	{

	}

	SafePtr(const SafePtr& other)
	{
		m_p = other.m_p;
	}
	~SafePtr()
	{
		m_tr.destroy(m_p);
	}
	SafePtr& operator = (_Ptr p)
	{
		if (!m_tr.equal_to(m_p, p))
		{
			m_tr.destroy(m_p); m_p = p;
		}
		return *this;
	}
	_Ptr detach()
	{
		_Ptr tmp = m_p;
		m_p = (_Ptr)m_tr.default_value();
		return tmp;
	}
	void dispose()
	{
		m_tr.destroy(m_p);
		m_p = (_Ptr)m_tr.default_value();
	}
	operator _Ptr () const
	{
		return m_p;
	}
	_Ptr operator -> () const
	{
		return m_p;
	}

	_Ptr ptr()
	{
		return m_p;
	}
	const _Ptr ptr() const
	{
		return m_p;
	}

public:
	_Ptr m_p;
	_Traits m_tr;
};

#define UCharArrayPtr	SafePtr<unsigned char*, default_array_safeptr>
#define CharArrayPtr	SafePtr<char*, default_array_safeptr>
#define UCharPtr		SafePtr<unsigned char*, default_free_safeptr>
#define CharPtr		SafePtr<char*, default_free_safeptr>
#define WCharPtr		SafePtr<wchar_t*, default_free_safeptr>

#if(TARGET_OS == OS_WINDOWS)

struct hmodule_safeptr
{
	static HMODULE default_value() { return 0; }
	static bool equal_to(HMODULE l, HMODULE r) { return l == r; }
	static void destroy(HMODULE mod) {
		if (mod)
			::FreeLibrary(mod);
	}
};

#define DynamiclibPtr	SafePtr<HMODULE, hmodule_safeptr>

struct handle_safeptr
{
	static HANDLE default_value() { return 0; }
	static bool equal_to(HANDLE l, HANDLE r) { return l == r; }
	static void destroy(HANDLE handle) {
		if (handle)
			::CloseHandle(handle);
	}
};

#define CHandlePtr	SafePtr<HANDLE, handle_safeptr>


struct file_handle_safeptr
{
	static HANDLE default_value() { return INVALID_HANDLE_VALUE; }
	static bool equal_to(HANDLE l, HANDLE r) { return l == r; }
	static void destroy(HANDLE h) {
		if (INVALID_HANDLE_VALUE != h)
			::CloseHandle(h);
	}
};

#define FileHandlePtr	SafePtr<HANDLE, file_handle_safeptr>

struct find_handle_safeptr
{
	static HANDLE default_value() { return INVALID_HANDLE_VALUE; }
	static bool equal_to(HANDLE l, HANDLE r) { return l == r; }
	static void destroy(HANDLE h) {
		if (INVALID_HANDLE_VALUE != h)
			::FindClose(h);
	}
};

#define FindFileHandlePtr	SafePtr<HANDLE, find_handle_safeptr>

struct socket_handle_safeptr
{
	static _sock_t default_value() { return INVALID_SOCKET; }
	static bool equal_to(_sock_t l, _sock_t r) { return l == r; }
	static void destroy(_sock_t h) {
		if (INVALID_SOCKET != h)
			::closesocket(h);
	}
};

#define SocketHandlePtr	SafePtr<_sock_t, socket_handle_safeptr>

struct filemapping_safeptr
{
	static void* default_value() { return 0; }
	static bool equal_to(HANDLE l, HANDLE r) { return l == r; }
	static void destroy(HANDLE p) {
		if (p != NULL)
			::UnmapViewOfFile(p);
	}
};

#define MappingHandlePtr	SafePtr<HANDLE, filemapping_safeptr>


#elif(TARGET_OS == OS_POSIX)

struct hmodule_safeptr
{
	static HMODULE default_value() { return 0; }
	static bool equal_to(HMODULE l, HMODULE r) { return l == r; }
	static void destroy(HMODULE h) { if (h) dlclose(h); }
};

#define DynamiclibPtr	SafePtr<HMODULE, hmodule_safeptr>

struct socket_handle_safeptr
{
	static _sock_t default_value() { return INVALID_SOCKET; }
	static bool equal_to(_sock_t l, _sock_t r) { return l == r; }
	static void destroy(_sock_t h) { if (INVALID_SOCKET != h) ::close(h); }
};

#define SocketHandlePtr	SafePtr<_sock_t, socket_handle_safeptr>

#elif(TARGET_OS == OS_DARWIN)

struct hmodule_safeptr
{
    static HMODULE default_value() { return 0; }
    static bool equal_to(HMODULE l, HMODULE r) { return l == r; }
    static void destroy(HMODULE h) { if (h) dlclose(h); }
};

#define DynamiclibPtr    SafePtr<HMODULE, hmodule_safeptr>

#endif






#endif


#endif
